import { cloneDeep, isNull, isEmpty, isUndefined, get, merge } from 'lodash'

import GlobalConfig from '../base-options'
import { getType } from '../utils'
import { color } from '../base-options'
import BaseEcharts from '../components/BaseEcharts.vue'
import EmptyData from '../components/EmptyData.vue'
import LoadingChart from '../components/LoadingChart.vue'
import createChartData from '../utils/createChartData.js'

export default {
  components: {
    BaseEcharts,
    EmptyData,
    LoadingChart
  },
  props: {
    data: {
      type: [Object, Array],
      default() {
        return {
          dimensions: { data: [] },
          measures: [],
        }
      }
    },
    settings: {
      type: [Object, Array],
      default() {
        return {}
      }
    },
    // echarts default options
    title: Object,
    legend: Object,
    grid: Object,
    xAxis: [Object, Array],
    yAxis: [Object, Array],
    polar: Object,
    radiusAxis: Object,
    angleAxis: Object,
    radar: [Object, Array],
    dataZoom: [Object, Array],
    visualMap: [Object, Array],
    tooltip: Object,
    axisPointer: Object,
    toolbox: Object,
    brush: Object,
    geo: Object,
    parallel: Object,
    parallelAxis: Array,
    singleAxis: Array,
    timeline: Object,
    graphic: Object,
    calendar: Object,
    dataset: Object,
    series: [Object, Array],
    color: Array,
    backgroundColor: [Object, String],
    textStyle: Object,
    animation: Object,
    animationThreshold: Number,
    animationDuration: [Number, Function],
    animationEasing: [String, Function],
    animationDelay: [Number, Function],
    animationDurationUpdate: [Number, Function],
    animationEasingUpdate: [String, Function],
    animationDelayUpdate: [String, Function],
    blendMode: String,
    hoverLayerThreshold: Number,
    useUTC: { type: Boolean, default: false },
    tooltipVisible: { type: Boolean, default: true },
    legendVisible: { type: Boolean, default: true },
    tickMarkVisible: { type: Boolean, default: false }, // 雷达图是否显示刻度
    legendPosition: String,
    theme: [String, Object],
    loading: { type: Boolean, default: false },
    emptyText: String,
    renderer: { type: String, default: 'canvas' },
    height: { type: Number, default: 400 },
    seriesOption: {
      type: Object,
      default() {
        return {}
      }
    },

    //通用平台参数
    loadOptions: {
      type: Object,
      default: () => {
        return {}
      }
    },
    locking: {
      type: Boolean,
      default: false
    },
    beforeDataLoad: {
      type: Function,
      default: null
    },
    beforeChartLoad: {
      type: Function,
      default: null
    }
  },
  data() {
    return {
      // echarts instance
      ec: null,
      initOptions: null,
      showLoading: this.loading,

      // 通用平台获取的数据
      chartType: '', // 图表类型
      chartOptions: {}, // 通用平台 图表配置
      chartData: {} // 通用平台 图表数据
    }
  },
  computed: {
    chartColor() {
      return this.theme ? this.color : this.color || color
    },
    isEmptyData() {
      if (isNull(this.chartData) || isEmpty(this.chartData) || isUndefined(this.chartData)) {
        return true
      } else {
        if (Array.isArray(this.chartData)) {
          return false
        } else {
          const measures = get(this.chartData, 'measures')
          return measures.length === 0
        }
      }
    },
    isEmptySeries() {
      return isNull(this.series) || isEmpty(this.series) || isUndefined(this.series)
    },
    isHasData() {
      return !this.isEmptyData || !this.isEmptySeries
    },
    isHasParentStyle() {
      return this.showLoading || (this.isEmptyData && this.isEmptySeries)
    },
    parentStyle() {
      const parentStyle = this.isHasParentStyle ? { position: 'relative', height: `${this.height}px` } : {}
      return parentStyle
    }
  },
  watch: {
    data: {
      deep: true,
      handler(v) {
        if (v) {
          this.chartData = v
        }
      }
    },
    chartData: {
      deep: true,
      handler(v) {
        if (v) {
          this.dataHandler(v)
        }
      }
    },
    settings: {
      deep: true,
      handler(v) {
        this.dataHandler(this.chartData)
      }
    },
    ec(val) {
      this.$emit('update:ec', val)
    },
    loading(v) {
      this.showLoading = v
    }
  },
  methods: {
    dataHandler(data) {
      if (!this.chartHandler || (this.isEmptyData && this.isEmptySeries)) return
      const extra = {
        tooltipVisible: this.tooltipVisible,
        legendVisible: this.legendVisible,
        isEmptyData: this.isEmptyData,
        isEmptySeries: this.isEmptySeries,
        tickMarkVisible: this.tickMarkVisible,
        _once: this._once
      }
      if (this.beforeConfig) data = this.beforeConfig(data)

      // 加入通用查询平台的配置，页面配置的优先级最高
      this.chartOptions.settings = Object.assign({}, this.chartOptions.settings, this.settings)
      const options = this.chartHandler(data, cloneDeep(this.chartOptions.settings), extra)

      if (options) {
        if (typeof options.then === 'function') {
          options.then(this.optionsHandler)
        } else {
          this.optionsHandler(options)
        }
      }
      this.showLoading = false
    },
    optionsHandler(options) {
      options.color = this.chartColor
      // handle legend
      if (this.legendPosition && options.legend) {
        const position = this.legendPosition.split('-').shift()
        options.legend.left = this.legendPosition.split('-').pop()
        if (['top'].indexOf(position) !== -1) options.legend.top = 0
        if (['bottom'].indexOf(position) !== -1) options.legend.bottom = 0
      }
      const echartsSettings = [
        'title',
        'legend',
        'grid',
        'xAxis',
        'yAxis',
        'polar',
        'radiusAxis',
        'angleAxis',
        'radar',
        'dataZoom',
        'visualMap',
        'tooltip',
        'axisPointer',
        'toolbox',
        'brush',
        'geo',
        'parallel',
        'parallelAxis',
        'singleAxis',
        'timeline',
        'graphic',
        'calendar',
        'dataset',
        'series',
        'color',
        'backgroundColor',
        'textStyle',
        'animation',
        'animationThreshold',
        'animationDuration',
        'animationEasing',
        'animationDelay',
        'animationDurationUpdate',
        'animationEasingUpdate',
        'animationDelayUpdate',
        'blendMode',
        'hoverLayerThreshold',
        'useUTC'
      ]
      echartsSettings.forEach((setting) => {
        // 判断默认的配置是否强制覆盖，isForce为true则使用object.assign合并
        if (this[setting]) {
          options[setting] = options[setting]?.isForce ? Object.assign({}, options[setting], this[setting]) : this[setting]
          options[setting]?.isForce && delete options[setting]?.isForce
        }
      })
      if (this.animation) {
        Object.keys(this.animation).forEach((key) => {
          options[key] = this.animation[key]
        })
      }
      options.series = this.seriesHandler(options.series)
      // Merge options
      this.options = Object.assign(cloneDeep(this.options), options)
    },
    seriesHandler(series) {
      // 当 series 系列为空数组
      if (Array.isArray(series) && series.length === 0) return []

      // 当 series 为对象时，初始化为数组
      if (!(series instanceof Array)) return [series]

      // 当未配置 seriesOption 系列配置时
      if (Object.keys(this.seriesOption).length === 0) return series

      // 合并 series 配置
      for (const [key, opt] of Object.entries(this.seriesOption)) {
        const _idx = series.findIndex((v) => v.name === key)
        if (_idx > -1) merge(series[_idx], opt)
      }
      return series
    },
    init() {
      if (this.chartData) this.dataHandler(this.chartData)
    },
    addWatchToProps() {
      const watchedVariable = this._watchers.map((watcher) => watcher.expression)
      Object.keys(this.$props).forEach((prop) => {
        if (!~watchedVariable.indexOf(prop)) {
          const opts = {}
          if (getType(prop) === '[object Object]') {
            opts.deep = true
          }
          this.$watch(
            prop,
            () => {
              this.dataHandler(this.data)
            },
            opts
          )
        }
      })
    },

    // 通用平台 获取图表配置
    async getChartOption() {
      this.showLoading = true
      return new Promise(async (resolve, reject) => {
        if (GlobalConfig.request) {
          try {
            const res = await GlobalConfig.request({
              url: this.loadOptions.chartUrl,
              method: 'post',
              data: this.loadOptions.chartFormData ? this.loadOptions.chartFormData : {}
            })
            if (res) {
              let data = res.data.payload
              // 根据图表类型，获取对应类型的配置
              let [chart] = data.filter((item) => {
                return item.chartsType === this.chartType
              })
              // 获取到的数据暂存起来
              this.chartOptions = chart
                ? {
                    ...chart,
                    settings: chart.settings && chart.settings !== '' ? JSON.parse(chart.settings) : {},
                    settingsForArea:
                      chart.settingsForArea && chart.settingsForArea !== '' ? JSON.parse(chart.settingsForArea) : {}
                  }
                : {}

              this.$emit('onChartLoaded', this.chartOptions)
              resolve()
            } else {
              reject()
            }
          } catch (error) {
            resolve()
            this.$emit('onChartLoaded')
            return false
          }
        }
      })
    },

    // 通用平台 获取图表数据
    async getChartData() {
      this.showLoading = true
      return new Promise(async (resolve, reject) => {
        if (GlobalConfig.request) {
          try {
            const res = await GlobalConfig.request({
              url: this.loadOptions.dataUrl,
              method: 'post',
              data: this.loadOptions.formData ? this.loadOptions.formData : {}
            })

            if (res) {
              // 构造数据
              let { data } = res.data.payload
              typeof this.beforeDataLoad === 'function' && (data = this.beforeDataLoad(data))
              // 根据不同数据类型，构造不同的图表数据
              let chart = new createChartData(this, this.chartOptions)
              let chartData = chart.create(data, this.chartType, this)
              typeof this.beforeChartLoad === 'function' && (chartData = this.beforeChartLoad(chartData))
              this.chartData = Object.assign({}, this.data, chartData)
              
              let { legend } = chart
              legend && this.legend && Object.assign(this.legend, legend)

              this.$emit('onDataLoaded', this.chartData)
              resolve()
            } else {
              reject()
            }
          } catch (error) {
            this.$emit('onDataLoaded')
            reject()
            return false
          }
        }
      })
    },

    loadData(data) {
      this.chartData = data
    },

    getData() {
      return this.chartData
    }
  },
  created() {
    // init options
    this.initOptions = {
      renderer: this.renderer
    }
    this._once = {}
    this.addWatchToProps()
  },
  mounted() {
    const reg = new RegExp(`${GlobalConfig.tagPrefix}`, 'gi')
    const type = this.$vnode.componentOptions.tag.replace(reg, '').toLowerCase()
    this.chartType = type
    // 没有设置loadOptions，代表不走通用查询
    if (isEmpty(this.loadOptions)) {
      this.chartData = Array.isArray(this.data) ? [].concat(this.data) : Object.assign({}, this.data)
      this.init()
    } else {
      this.getChartOption().then(() => {
        !this.locking
          ? this.getChartData().then(() => {
              this.init()
            })
          : this.init()
      })
    }
  }
}
